home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / c / db / DbLockDesc.c < prev    next >
C/C++ Source or Header  |  1989-11-05  |  6KB  |  246 lines

  1. /* 
  2.  * DbLockDesc.c --
  3.  *
  4.  *    Source code for the DbLockDesc procedure.
  5.  *
  6.  * Copyright 1988 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/lib/c/db/RCS/DbLockDesc.c,v 1.7 89/07/31 17:42:10 douglis Exp $ SPRITE (Berkeley)";
  18. #endif not lint
  19.  
  20.  
  21. #include <db.h>
  22. #include "dbInt.h"
  23. #include <sys/signal.h>
  24. #include <sys/time.h>
  25. #include <stdio.h>
  26.  
  27. #ifndef CLEAN
  28. int db_Contention = 0;
  29. #endif /* CLEAN */
  30.  
  31. /*
  32.  * Set the default timeout, in seconds.
  33.  */
  34. #ifndef DB_LOCK_TIMEOUT
  35. #define DB_LOCK_TIMEOUT 10
  36. #endif /* DB_LOCK_TIMEOUT */
  37.  
  38. /*
  39.  *----------------------------------------------------------------------
  40.  *
  41.  * AlarmHandler --
  42.  *
  43.  *    Routine to service a SIGALRM signal.  This routine disables
  44.  *    the alarm (letting the caller reenable it when appropriate).
  45.  *
  46.  * Results:
  47.  *    None.
  48.  *
  49.  * Side effects:
  50.  *    The alarm is disabled.
  51.  *
  52.  *----------------------------------------------------------------------
  53.  */
  54. static int
  55. AlarmHandler()
  56. {
  57.     
  58.     alarm(0);
  59. #ifdef DEBUG
  60.     syslog(LOG_INFO, "Database lock timed out.");
  61. #endif /* DEBUG */
  62.     (void) signal (SIGALRM, SIG_IGN);
  63. }
  64.  
  65.  
  66. /*
  67.  *----------------------------------------------------------------------
  68.  *
  69.  * DbLockDesc --
  70.  *
  71.  *    Lock a file descriptor, polling if necessary, and potentially
  72.  *    breaking the lock if timeout occurs.
  73.  *
  74.  * Results:
  75.  *    If the file is locked, by hook or by crook,
  76.  *    0 is returned.  If the file is not successfully locked,
  77.  *    -1 indicates an error and errno gives a more specific error.
  78.  *
  79.  * Side effects:
  80.  *    None.
  81.  *
  82.  *----------------------------------------------------------------------
  83.  */
  84.  
  85. int
  86. DbLockDesc(handlePtr)
  87.     Db_Handle *handlePtr;
  88. {
  89.     int streamID;            /* file descriptor */
  90.     int type;                /* type of lock */
  91.     Db_LockHow action;        /* DB_LOCK_{POLL,BLOCK,NO_BLOCK,WAIT,NONE} */
  92.     int status;
  93.     struct itimerval itimer, oldItimer;
  94.     int (*oldHandler) ();
  95.     int error;
  96.     static int syslogDone = 0;
  97.  
  98.  
  99.     streamID = handlePtr->streamID;
  100.     action = handlePtr->lockHow;
  101.     type = handlePtr->lockType;
  102.     
  103.     if (action == DB_LOCK_NONE) {
  104.     return(0);
  105.     }
  106.     if (action != DB_LOCK_WAIT) {
  107.     type |= LOCK_NB;
  108.     }
  109.     /*
  110.      * Try the lock, then set a timer and try again.
  111.      *
  112.      * If the lock call times out in the RPC, return SUCCESS to keep the caller
  113.      * from aborting.
  114.      */
  115.     
  116.     status = flock(streamID, type);
  117.     if (status == -1) {
  118.     /*
  119.      * It is possible to get a sprite RPC_TIMEOUT condition, or other
  120.      * obscure error, which will map to EINVAL by default.  We're mostly
  121.      * interested in the EWOULDBLOCK condition, so if we get something
  122.      * we know is likely to be innocuous, return 0.  In particular,
  123.      * we don't want our caller to abort because the lock timed out, since
  124.      * it can wait for recovery.
  125.      */
  126.     if (errno == EINVAL) {
  127.         return(0);
  128.     } 
  129.     if ((errno != EWOULDBLOCK) || (action == DB_LOCK_NO_BLOCK)) {
  130.         return(-1);
  131.     }
  132.     } else {
  133.     return(0);
  134.     }
  135.  
  136.     /*
  137.      * Now lock in blocking mode, with an interval timer around to wake
  138.      * us up if need be.
  139.      */
  140. #ifndef CLEAN
  141.     db_Contention++;
  142. #endif
  143.  
  144.     type &= ~LOCK_NB;
  145.     itimer.it_interval.tv_sec = 0;
  146.     itimer.it_interval.tv_usec = 0;
  147.     itimer.it_value.tv_sec = DB_LOCK_TIMEOUT;
  148.     itimer.it_value.tv_usec = 0;
  149.  
  150.     oldHandler = (int (*)()) signal(SIGALRM, AlarmHandler);
  151.     if (oldHandler == (int (*)()) -1) {
  152.     syslog(LOG_ERR, "Error setting signal handler.");
  153.     return(-1);
  154.     }
  155.     if (setitimer(ITIMER_REAL, &itimer, &oldItimer) == -1) {
  156.     error = errno;
  157.     (void) signal(SIGALRM, oldHandler);
  158.     errno = error;
  159.     return(-1);
  160.     }
  161. #ifdef LOCK_DEBUG
  162.     syslog(LOG_INFO, "Debug msg: DB doing blocking lock with timeout.");
  163. #endif
  164.  
  165.     status = flock(streamID, type);
  166.  
  167. #ifdef LOCK_DEBUG
  168.     syslog(LOG_INFO, "Debug msg: blocking lock with timeout returned %d, errno %d.", status, errno);
  169. #endif
  170.  
  171.     error = errno;
  172.     if (setitimer(ITIMER_REAL, &oldItimer, (struct itimerval *) NULL) == -1) {
  173.     return(-1);
  174.     }
  175.     (void) signal(SIGALRM, oldHandler);
  176.     if (status == -1) {
  177.     errno = error;
  178.     if (errno == EINVAL || errno == 0) {
  179.         return(0);
  180.     }
  181.     if (errno != EINTR) {
  182.         return(status);
  183.     }
  184.     if (action == DB_LOCK_POLL) {
  185.         errno = ETIMEDOUT;
  186.         return(-1);
  187.     }
  188. #ifndef CLEAN
  189.     if (!syslogDone) {
  190.         syslog(LOG_INFO, "DbLockDesc: lock timed out (file %s).\n",
  191.            handlePtr->fileName);
  192.         syslogDone = 1;
  193.     }
  194. #endif /* CLEAN */
  195.  
  196.     /*
  197.      * Break the lock if required.  Try to break an exclusive lock.  If
  198.      * that fails, and we were trying to get an exclusive lock, then try
  199.      * releasing a shared lock since that could have been the problem.
  200.      * Then try to get the lock again.
  201.      * Return EWOULDBLOCK if breaking the lock wasn't successful.
  202.      *
  203.      * This has been commented out because one may no longer break
  204.      * locks on behalf of other processes.
  205.      */
  206.     if (action == DB_LOCK_BREAK) {
  207.         status = flock(streamID, LOCK_EX | LOCK_NB | LOCK_UN);
  208.         if ((status != 0) && (type & LOCK_EX)) {
  209.         (void) flock(streamID, LOCK_SH | LOCK_NB | LOCK_UN);
  210.         }
  211.     }
  212.     status = flock(streamID, type | LOCK_NB);
  213.     if (status == 0) {
  214.         return(0);
  215.     } else if (errno != EWOULDBLOCK) {
  216.         return(status);
  217.     } else {
  218. #ifdef CLEAN
  219.         syslog(LOG_WARNING, "DbLockDesc: unable to lock stream %d in %s mode",
  220.            streamID, (type & LOCK_EX) ? "exclusive" : "shared");
  221. #else /* CLEAN */
  222.         syslog(LOG_WARNING, "DbLockDesc: unable to lock file %s in %s mode",
  223.            handlePtr->fileName,
  224.            (type & LOCK_EX) ? "exclusive" : "shared");
  225. #endif /* CLEAN */
  226.     }
  227.  
  228. /*
  229.  * Once this thing is really production quality, it should return an error
  230.  * if the lock times out.  For now, especially as long as processes can go
  231.  * into the debugger with a lock held, just return success anyway.  We
  232.  * tried.
  233.  */
  234.  
  235. #ifdef INSTALLED
  236.     errno = EWOULDBLOCK;
  237.     return (-1);
  238. #else /* INSTALLED */
  239.     return(0);
  240. #endif /* INSTALLED */
  241.     }
  242.     return(0);
  243. }
  244.  
  245.  
  246.